package cn.net.yugu.doraemon.springweb.exception;

import cn.net.yugu.doraemon.api.common.response.DataResult;
import cn.net.yugu.doraemon.springweb.config.YgWebProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.ServletException;
import java.util.stream.Collectors;

/**
 * @description: 统一异常捕获.
 * @author: wanghongli
 * @create: 2023-03-09 16:17:56
 */
@Slf4j
@RestControllerAdvice
public class CommonExceptionHandler {
    @Autowired
    private YgWebProperties ygWebProperties;

    /**
     * 捕获 自定 异常
     */
    @ExceptionHandler({BusinessException.class})
    public DataResult<?> handleBusinessException(BusinessException ex) {
        log.error(ex.getMessage(), ex);
        if (!ygWebProperties.isUnionExceptionWrapperEnable()) {
            throw ex;
        }
        if (ygWebProperties.isUseCommonErrorMsgEnable()) {
            return DataResult.failWithMessage(ex.getErrCode(), ygWebProperties.getCommonErrorMsg());
        }
        return DataResult.failWithMessage(ex.getErrCode(), ex.getMessage());
    }

    /**
     * 参数缺失异常
     * 说明：参数为必填时，若入参中无此参数则会报MissingServletRequestParameterException
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public DataResult<?> handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) throws MissingServletRequestParameterException {
        log.error(ex.getMessage(), ex);
        if (!ygWebProperties.isUnionExceptionWrapperEnable()) {
            if (ygWebProperties.isUseCommonErrorMsgEnable()) {
                throw new RuntimeException(ygWebProperties.getCommonErrorMsg());
            }
            throw ex;
        }
        if (ygWebProperties.isUseCommonErrorMsgEnable()) {
            return DataResult.failWithMessage(ygWebProperties.getCommonErrorCode(), ygWebProperties.getCommonErrorMsg());
        }
        return DataResult.failWithMessage(ex.getMessage());
    }

    /**
     * 参数值类型异常
     * 说明: 定义Integer类型，输入的为String，会出现 MethodArgumentTypeMismatchException异常
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public DataResult<?> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {
        log.error(ex.getMessage(), ex);
        if (!ygWebProperties.isUnionExceptionWrapperEnable()) {
            if (ygWebProperties.isUseCommonErrorMsgEnable()) {
                throw new RuntimeException(ygWebProperties.getCommonErrorMsg());
            }
            throw ex;
        }
        if (ygWebProperties.isUseCommonErrorMsgEnable()) {
            return DataResult.failWithMessage(ygWebProperties.getCommonErrorCode(), ygWebProperties.getCommonErrorMsg());
        }
        String message = "参数:" + ex.getName() + " 类型错误";
        return DataResult.failWithMessage(message);
    }

    /**
     * {@code @RequestBody} 参数校验不通过时抛出的异常处理
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public DataResult<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) throws MethodArgumentNotValidException {
        log.error(ex.getMessage(), ex);
        if (!ygWebProperties.isUnionExceptionWrapperEnable()) {
            if (ygWebProperties.isUseCommonErrorMsgEnable()) {
                throw new RuntimeException(ygWebProperties.getCommonErrorMsg());
            }
            throw ex;
        }
        if (ygWebProperties.isUseCommonErrorMsgEnable()) {
            //spring参数校验不改变错误信息
            return DataResult.failWithMessage(ygWebProperties.getCommonErrorCode(), ygWebProperties.getCommonErrorMsg());
        }
        String msg = ex.getBindingResult().getFieldErrors().stream()
            .map(f -> f == null ? "null" : f.getField() + ": " + f.getDefaultMessage())
            .collect(Collectors.joining(", "));
        return DataResult.failWithMessage(msg);
    }


    /**
     * 顶级异常捕获并统一处理，当其他异常无法处理时候选择使用
     */
    @ExceptionHandler({Exception.class})
    public DataResult<?> handle(Exception ex) throws Exception {
        log.error(ex.getMessage(), ex);
        if (!ygWebProperties.isUnionExceptionWrapperEnable()) {
            if (ygWebProperties.isUseCommonErrorMsgEnable()) {
                throw new RuntimeException(ygWebProperties.getCommonErrorMsg());
            }
            throw ex;
        }
        if (ygWebProperties.isUseCommonErrorMsgEnable()) {
            return DataResult.failWithMessage(ygWebProperties.getCommonErrorCode(), ygWebProperties.getCommonErrorMsg());
        }
        return DataResult.failWithMessage(ex.getMessage());
    }

    /**
     * 处理已知的系统异常
     */
    @ExceptionHandler({ServletException.class})
    public DataResult<?> handle1(Exception ex) throws Exception {
        log.error(ex.getMessage(), ex);
        if (!ygWebProperties.isUnionExceptionWrapperEnable()) {
            if (ygWebProperties.isUseCommonErrorMsgEnable()) {
                throw new RuntimeException(ygWebProperties.getCommonErrorMsg());
            }
            throw ex;
        }
        if (ygWebProperties.isUseCommonErrorMsgEnable()) {
            return DataResult.failWithMessage(ygWebProperties.getCommonErrorCode(), ygWebProperties.getCommonErrorMsg());
        }
        return DataResult.failWithMessage(ex.getMessage());
    }
}
